#include <stdlib.h>
#include <string.h>
#include "flvio.h"
#include "scan.h"

/**
 * do_context() - maintain contextual information of current hdr or tag
 */
static void do_context(const struct tagbuf *b, struct context *ctx)
{
	if (!flv_is_tag(b))
		return;

	ctx->tag[1] = ctx->tag[0];
	ctx->tag[0].ord = ctx->tag[1].ord + 1;
	ctx->tag[0].time = flv_time(b);
	ctx->tag[0].track = flv_track(b);

	if (ctx->tag[0].track == FLV_TRACK_VIDEO &&
	flv_vframe(b) == FLV_VIDEO_KEY) {
		ctx->gop[1] = ctx->gop[0];
		ctx->gop[0].ord = ctx->gop[1].ord + 1;
		ctx->gop[0].first = ctx->tag[0];
	} else if (ctx->tag[0].ord == 1) {
		/* non-keyframe first tag: virtual gop 0 */
		ctx->gop[0].first = ctx->tag[0];
	}
	ctx->gop[0].last = ctx->tag[0];
}

/**
 * scan() - generic flv stream scanning method for callbacks
 * @return: -1 on errors
 *
 * The callback is called
 * - once before begining reading stream,
 * - each time when a hdr or tag is read,
 * - once after finishing reading stream.
 *
 * scan() aborts with -1 if callback returns ERROR.
 */
int scan(FILE *in, FILE *out, scan_callback cb)
{
	struct tagbuf *b;
	struct context ctx[1];
	scan_verdict verdict;

	b = tagbuf_alloc();
	if (!b)
		return -1;
	memset(ctx, 0, sizeof(*ctx));
	ctx->file_in = in;
	ctx->file_out = out;

	if (cb(BEFORE, 0, 0) == ERROR)
		goto err;

	while (!feof(in)) {
		if (read_tag(in, b, ctx->tag[0].ord != 0) < 0) {
			if (feof(in))
				break;
			else
				goto err;
		}
			

		do_context(b, ctx);

		verdict = cb(flv_is_tag(b) ? TAG : HDR, b, ctx);
		in = ctx->file_in;
		out = ctx->file_out;

		switch (verdict) {
		case OUTPUT:
			if (write_tag(out, b) < 0)
				goto err;
			break;
		case ERROR:
			goto err;
		case DISCARD:
		default:
			break;
		}
	}

	if (cb(AFTER, 0, ctx) == ERROR)
		goto err;

	tagbuf_free(b);
	return 0;
err:
	tagbuf_free(b);
	return -1;
}
